package me.zhengjie.modules.enrstu.service.impl;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.text.StrFormatter;
import cn.hutool.core.util.IdcardUtil;
import cn.hutool.core.util.ObjectUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.exception.BadRequestException;

import me.zhengjie.modules.enrstu.domain.*;
import me.zhengjie.modules.enrstu.repository.AdministrativeDivisionRepository;
import me.zhengjie.modules.enrstu.service.*;
import me.zhengjie.modules.enrstu.service.dto.*;
import me.zhengjie.modules.system.domain.Dept;
import me.zhengjie.modules.system.domain.User;
import me.zhengjie.modules.system.repository.DeptRepository;
import me.zhengjie.modules.system.repository.UserRepository;
import me.zhengjie.utils.DateUtils;
import me.zhengjie.utils.SecurityUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.time.Duration;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class SignUpServiceImpl implements SignUpService {
    private final AdministrativeDivisionService administrativeDivisionCommonService;
    private final EnrollmentParameterService enrollmentParameterCommonService;
    private final CommunityService comService;
    private final ChildrenInformationService chiService;
    private final FileInformationService fileInformationService;
    private final GuardianInformationService guardianInformationService;
    private final ReviewInformationService reviewInformationCommonService;
    private final ManageService manageService;
    private final GuardianChildrenService gcService;
    private final SchoolService slService;
    private final ReviewInformationLogService rlService;
    private final SchoolService sclService;
    private final AdministrativeDivisionRepository adRepository;
    private  final DeptRepository deptRepository;
    private final UserRepository userRepository;
    private String childrenInformationId;



    @Override
    public List<AdministrativeDivisionDto> findAdministrativeDivision(Long administrativeDivisionId) {

        List<AdministrativeDivisionDto> administrativeDivisionList;
        //administrativeDivisionId为空，查询所有省列表
        if (administrativeDivisionId == null) {
            administrativeDivisionList = administrativeDivisionCommonService.findByDivisionLevel(10).stream().map(administrativeDivision -> {
                AdministrativeDivisionDto administrativeDivisionDto = new AdministrativeDivisionDto();
                BeanUtils.copyProperties(administrativeDivision, administrativeDivisionDto);
                return administrativeDivisionDto;
            }).collect(Collectors.toList());
        }else {
            //administrativeDivisionId不为空，查询该行政区的下级行政区
            administrativeDivisionList = administrativeDivisionCommonService.findByIdsublevelList(administrativeDivisionId).stream().map(administrativeDivision -> {
                AdministrativeDivisionDto administrativeDivisionDto = new AdministrativeDivisionDto();
                BeanUtils.copyProperties(administrativeDivision, administrativeDivisionDto);
                return administrativeDivisionDto;
            }).collect(Collectors.toList());

        }
        return administrativeDivisionList;
    }


    @Override
    public List<EnrollmentParameterDto> findByTypeLabel(String label) {
        return enrollmentParameterCommonService.findByTypeLabel(label);
    }

    @Override
    public List<SchoolDto> findSchoolList(Long communityAdId,boolean isPolicyCare) {
        return slService.findSchoolList(communityAdId,isPolicyCare);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveOrSubmit(SignUpReportInfoRequest request, List<MultipartFile> files) {

        //0.校验数据正确性
        saveCheck(request,files);
        //一、提交
        if (request.isSubmit()){
            //1、再进行一次saveOrUpdate操作，谨防用户第一次直接点提交，没有点保存，或者存在需要更新的数据
            String childrenId = this.saveOrUpdate(request, files);
            //2.提交,获取ReviewInformation审核id，并保存在儿童信息表中
            ReviewInformation reviewInformation = reviewInformationCommonService.create(childrenId);
            ChildrenInformationDto childrenInformationDto = chiService.findById(childrenId);
            ChildrenInformation childrenInfo = new ChildrenInformation();
            BeanUtils.copyProperties(childrenInformationDto, childrenInfo);
            childrenInfo.setInfId(reviewInformation.getId());
            chiService.update(childrenInfo);
            return true;
        }else {
            //二、保存
            return this.saveOrUpdate(request, files) != null;
        }
    }

    @Override
    public GuardianInformation getGuardianInfo(String idCard) {
        if (!IdcardUtil.isValidCard(idCard)){
            throw new BadRequestException("身份证号码不合法");
        }
        return guardianInformationService.findByCard(idCard);
    }

    @Override
    public String getPrompt() {
        //1.获取当前配置已启动项目
        ManageDto manageDto =manageService.findUserStartMg();
        if (ObjectUtil.isNull(manageDto.getId())){
            throw new BadRequestException("当前没有已启用项目");
        }

        //2.判断当前时间处于哪一个阶段，返回提示信息
        //离家长填报开始时间还剩XX天”
        Date date = new Date();
        //离家长填报结束时间还剩XX天
        if (DateUtils.isIn(date, manageDto.getPmfParentFillStartTime(), manageDto.getPmfParentFillEndTime())){

            long diffMillis = DateUtils.between(date, manageDto.getPmfParentFillEndTime(), DateUnit.MS);
            return promptHandle("家长填报",diffMillis, false);
        }
        //离学校审核开始时间还剩XX天
        if(DateUtils.isIn(date, manageDto.getPmfParentFillEndTime(), manageDto.getPmfSchoolCheckStartTime())){
            long diffMillis = DateUtils.between(date, manageDto.getPmfSchoolCheckStartTime(), DateUnit.MS);
            return promptHandle("学校审核",diffMillis, true);
        }

        //离学校审核结束时间还剩XX天
        if(DateUtils.isIn(date, manageDto.getPmfSchoolCheckStartTime(), manageDto.getPmfSchoolCheckEndTime())){
            long diffMillis = DateUtils.between(date, manageDto.getPmfSchoolCheckEndTime(), DateUnit.MS);
            return promptHandle("学校审核",diffMillis, false);
        }
        //离教育局审核开始时间还剩XX天
        if(DateUtils.isIn(date, manageDto.getPmfSchoolCheckEndTime(), manageDto.getPmfEducationCheckStartTime())){
            long diffMillis = DateUtils.between(date, manageDto.getPmfEducationCheckStartTime(), DateUnit.MS);
            return promptHandle("教育局审核",diffMillis, true);
        }

        //离教育局审核结束时间还剩XX天
        if(DateUtils.isIn(date, manageDto.getPmfEducationCheckStartTime(), manageDto.getPmfEducationCheckEndTime())){
            long diffMillis = DateUtils.between(date, manageDto.getPmfEducationCheckEndTime(), DateUnit.MS);

            return promptHandle("教育局审核",diffMillis, false);
        }
        //离公布时间时间还剩XX天
        if(DateUtils.isIn(date, manageDto.getPmfEducationCheckEndTime(), manageDto.getPmfPublishTime())){
            long day = DateUtils.betweenDay(date, manageDto.getPmfPublishTime(), true);
            return promptHandle("公布",day, false);
        }
        if (DateUtils.compare(DateUtils.offsetDay(manageDto.getPmfParentFillStartTime(), -7),date) < 0){
            long diffMillis = DateUtils.between(manageDto.getPmfParentFillStartTime(), date, DateUnit.MS);
            return promptHandle("家长填报",diffMillis, true);
        }
        if(DateUtils.compare(manageDto.getPmfPublishTime()) < 0){
            return "您好，"+ SecurityUtils.getCurrentUser().getUsername() +"！ 本次小学生入学报名已圆满结束";
        }
        return null;
    }

    @Override
    public List<Map<String, Object>> getListAndDetail(String cliId) {
        List<Map<String, Object>> list = new ArrayList<>();
        //1.根据logId,获取儿童信息
        chiService.findByCliId(cliId).forEach(
            chi->{
                Map<String, Object> map = new HashMap<>();
                List<String> linkIds = new ArrayList<>();
                //2.根据儿童Id获取 监护人儿童关联关系中的所有监护人
                List<GuardianInformationDto> guards = gcService.findGuardianChildrenById(chi.getId());
                //3.获取附件信息
                linkIds.add(chi.getId());
                guards.forEach(guard -> linkIds.add(guard.getId()));
                List<FileInformation> files = fileInformationService.fileInfo(linkIds);
                //4.获取审核明细 TODO:等会修改成审核表
                List<ReviewInformationLog> rwLog = rlService.findByChildId(chi.getId());
                //5.获取儿童意向学校信息
                SchoolDto schoolDto = sclService.findById(chi.getSchoolId());
                map.put("chiInfo", chi);
                map.put("guardsInfo", guards);
                map.put("filesInfo", files);
                map.put("rwLogInfo", rwLog);
                map.put("schoolDto", schoolDto);
                list.add(map);
            }
        );
        //4.根据儿童id获取审核记录
        return list;
    }




    @Transactional(rollbackFor = Exception.class)
    public String saveOrUpdate(SignUpReportInfoRequest request, List<MultipartFile> files){
        ManageDto manageById = manageService.findUserStartMg();
        if (ObjectUtil.isNull(manageById)){
            throw new BadRequestException("当前没有可进行填报的招生项目");
        }
        // 1.保存/修改儿童信息
        if (ObjectUtil.isNotNull(request.getChildrenResources().getId())){
            chiService.update(request.getChildrenResources(),request.isSubmit());
            childrenInformationId = request.getChildrenResources().getId();
        }
        else {
            ChildrenInformation childrenInformation = new ChildrenInformation();
            BeanUtils.copyProperties(request.getChildrenResources(), childrenInformation);
            childrenInformationId = chiService.create(childrenInformation,request.isSubmit()).getId();
        }

        // 2.保存监护人信息
        String guardianInformationId = request.getGuardianResources().get(0).getId();
        if (ObjectUtil.isNotNull(guardianInformationId)){
            request.getGuardianResources().forEach(gu->{guardianInformationService.update(gu,request.isSubmit());});
        }else{
            List<GuardianInformation> guardianInformationList = request.getGuardianResources().stream().map(guardian->{
                GuardianInformation guardianInfo = guardianInformationService.create(guardian);
                //创建儿童-监护人关联表
                gcService.create(childrenInformationId, guardianInfo.getId());
                return guardianInfo;
            }).collect(Collectors.toList());
            guardianInformationId = guardianInformationList.get(0).getId();
        }

        // 3.保存附件信息
        String finalGuardianInformationId = guardianInformationId;
        log.info("request.getFileInfoCreateOrUpdate():{}",  request.getFileInfoCreateOrUpdate().size());
        request.getFileInfoCreateOrUpdate().forEach(fileInfoCreateOrUpdate -> {
            log.info("fileInfoCreateOrUpdate:{}", fileInfoCreateOrUpdate);
            //更新：LinkId不为空时更新附件
            if (ObjectUtil.isNotNull(fileInfoCreateOrUpdate.getLinkId()) && ObjectUtil.notEqual(fileInfoCreateOrUpdate.getLinkId(), "")){
                fileInformationService.fileUploadUpdate(files,fileInfoCreateOrUpdate);
            }else {
                //更新：LinkId为空时创建附件
                List<MultipartFile> collect = files.stream().filter(file -> {
                    //附件信息
                    String substring = Objects.requireNonNull(file.getOriginalFilename()).
                            substring(0, Objects.requireNonNull(file.getOriginalFilename()).
                                    indexOf('_', file.getOriginalFilename().indexOf('_') + 1));
                    return ObjectUtil.equal(fileInfoCreateOrUpdate.getFileAttachmentCode(), substring);
                }).collect(Collectors.toList());
                Boolean isChildrenFile = fileInfoCreateOrUpdate.getIsChildrenFile();
                //判断当前是儿童所关联的附件，还是监护人，提供对应的关联对象的id
                if (isChildrenFile){
                    fileInformationService.fileUploadCreate(collect, this.childrenInformationId,this.childrenInformationId,true);
                }else
                    //反之，则是监护人提供的附件，则上送一个监护人id即可
                    fileInformationService.fileUploadCreate(collect, this.childrenInformationId,finalGuardianInformationId, false);
            }

        });

        return childrenInformationId;
    }


    /**
     * 校验数据
     * @param request /
     * @param files /
     */
    private void saveCheck(SignUpReportInfoRequest request,List<MultipartFile> files){
        //0.填报时间是否在规定的时间范围内
        ManageDto manageById = manageService.findUserStartMg();
        if (ObjectUtil.isNull(manageById.getId())){
            throw new BadRequestException("当前没有可进行填报的招生项目");
        }
        if (DateUtils.compare(manageById.getPmfParentFillStartTime()) > 0){
            throw new BadRequestException("家长填报时间未开始");
        }
        if (DateUtils.compare(manageById.getPmfParentFillEndTime()) < 0){
            throw new BadRequestException("家长填报时间已结束");
        }
        //1.身份证合法性
        //判断儿童的身份证是否不为null，如果为是，则开始校验身份证的合法性，家长可能上送多个，所以需要判断措辞
        String childrenIdentityCard = request.getChildrenResources().getChildrenIdentityCard();
        if (ObjectUtil.isNotNull(childrenIdentityCard)){
            if(!IdcardUtil.isValidCard(childrenIdentityCard)){
                throw new BadRequestException("儿童：“" + request.getChildrenResources().getChildrenName() + "”的身份证不合法，请核对信息");
            };
        }
        //判断家长身份证是否不为null，家长信息可能上送多个，所以需要判断多次
        request.getGuardianResources().forEach(guardianInformation->{
            String guardianIdentityCard = guardianInformation.getGuardianIdentityCard();
            if(ObjectUtil.isNotNull(guardianIdentityCard)){
                if(!IdcardUtil.isValidCard(guardianIdentityCard)){
                    throw new BadRequestException("监护人：“" + guardianInformation.getGuardianName() + "”的身份证不合法，请核对信息");
                };
                return;
            };
        });
        //校验儿童信息
        if(ObjectUtil.isNotNull(request.getChildrenResources())){
            String chiName = request.getChildrenResources().getChildrenName();
            String chiAddress = request.getChildrenResources().getChildrenDomicileAddress();
            String chiHomeAddress = request.getChildrenResources().getChildrenHomeAddress();
            if(ObjectUtil.isNull(chiName) || ObjectUtil.isNotNull(chiAddress) || ObjectUtil.isNotNull(chiHomeAddress)){
                //儿童名称
                if (chiName.length() > 10){
                    throw new BadRequestException("儿童名称不能超过10个字符");
                }
                //户籍所在地地址
                if (chiAddress.length() > 50){
                    throw new BadRequestException("户籍所在地地址不能超过50个字符");
                }
                //家庭住址（居住证）
                if (chiHomeAddress.length() > 50){
                    throw new BadRequestException("家庭住址（居住证）不能超过50个字符");
                }
            }
        }
        //校验监护人信息
        if(!request.getGuardianResources().isEmpty()){
            request.getGuardianResources().forEach(guardianInformation->{
                String gN = guardianInformation.getGuardianName();
                String gM= guardianInformation.getGuardianMobile();
                String gWUnit = guardianInformation.getGuardianWorkUnit();
                if (ObjectUtil.isNotNull(gN) || ObjectUtil.isNotNull(gM) || ObjectUtil.isNotNull(gWUnit)){
                    //监护人名称
                    if (gN.length() > 10){
                        throw new BadRequestException("监护人名称不能超过10个字符");
                    }
                    //联系电话
                    Matcher m =  Pattern.compile("0?(13|14|15|18|17)[0-9]{9}").matcher(gM);
                    if (!m.matches()){
                        throw new BadRequestException("监护人联系电话不合法，请核对信息");
                    }
                    //单位
                    if (gWUnit.length() > 50){
                        throw new BadRequestException("单位不能超过50个字符");
                    }
                }
            });
        }


    }


    /**
     * 提示信息处理
     * @param isStart /
     * @return /
     */
    private String promptHandle(String segName,Long day, Boolean isStart){

        Duration duration = Duration.ofMillis(day);
        String timeUnit = "";
        long timeValue = 0;
        if(ObjectUtil.isNull(isStart)){
            //起始时间相关的提示语
            return  "您好，"+ SecurityUtils.getCurrentUser().getUsername() +"！离" + segName + "公布时间还剩"+ day +"天";
        }
        if (duration.toDays() >= 1) {
            // 时间差大于等于1天
            timeUnit = "天";
            timeValue = duration.toDays();
        }else if(duration.toHours() >= 1){
            timeUnit = "小时";
            timeValue = duration.toHours();
        }else if (duration.toMinutes() >= 1) {
            timeUnit = "分钟";
            timeValue = duration.toMinutes();
        }
        if (ObjectUtil.isNull(isStart)){
            return StrFormatter.format("您好,{}!离{}公布时间还剩{}{}", SecurityUtils.getCurrentUser().getUsername(),segName,timeValue,timeUnit);
        }
        String startOrEnd = isStart ? "开始时间" : "结束时间";
        return StrFormatter.format("您好,{}!离{}{}还剩{}{}", SecurityUtils.getCurrentUser().getUsername(),segName,startOrEnd,timeValue,timeUnit);
    }


}
